# uncompyle6 version 3.2.3
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.6.8 |Anaconda custom (64-bit)| (default, Feb 21 2019, 18:30:04) [MSC v.1916 64 bit (AMD64)]
# Embedded file name: helpers\custom_profiles.py
import re, logging, uuid, json, sqlalchemy.exc
from sqlalchemy import select as sql_select
from db.tables.profiles import ProfilesTable, ProfileRow
from settings_provider import settings

_logger = logging.getLogger("helpers.custom_profiles")
r_profile_scripting = re.compile("Scripting \\((.*?)\\)")
known_wvs_checks = None


def parse_wvs_checks(file_path):
    checks_by_key = dict()
    checks_by_path = dict()

    def parse_node(node, path=""):
        checks = node.get("checks")
        if checks:
            for check in checks:
                parse_node(check, ("/").join((path, check["key"])))

        else:
            checks_by_key[node["key"]] = dict(
                path=path, title=node["title"], key=node["key"]
            )
            checks_by_path[path] = dict(path=path, title=node["title"], key=node["key"])

    data = open(file_path, "rt").read()
    data = json.loads(data)
    parse_node(data)
    return dict(key=checks_by_key, path=checks_by_path)


def generate_profile_for_vuln_recheck(
    db, source, owner_id, creator_id, original_profile_id=None, vuln_id=None
):
    """
    :param vuln_id:
    :param db:
    :param creator_id:
    :param owner_id:
    :param original_profile_id:
    :param source: original vulnerability source
    :return:
        if we can't create a profile from source:
            - return None if we don't want to support recheck for this vulnerability
            - original_profile_id for use the original profile
        else:
            return a custom created profile
    """
    global known_wvs_checks
    if known_wvs_checks is None:
        try:
            known_wvs_checks = parse_wvs_checks(settings.get("wvs_checks_file_path"))
        except Exception as e:
            _logger.exception("parse_wvs_checks failed with %s", e)

        if known_wvs_checks is None:
            return original_profile_id
        check = known_wvs_checks["path"].get(source)
        if check is None:
            check = known_wvs_checks["key"].get(source)
        if check is None:
            m = r_profile_scripting.match(source)
            if m:
                if m.group(1):
                    check = known_wvs_checks["key"].get(m.group(1))
        if check is None:
            _logger.warning("Can't find check for %s:%s", source, vuln_id)
            return original_profile_id
        title = check["title"]
        title = title.replace(".script", "")
        title = title.replace("_", " ")
        profile_name = "Retest " + title
        jobs = dict(wvs=dict(profile="custom", checks=["+" + check["path"]]))
        profile_id = str(uuid.uuid4())
        profile_data = dict(
            profile_id=profile_id,
            owner_id=owner_id,
            creator_id=creator_id,
            name=profile_name,
            sort_order=-10,
            jobs=jobs,
        )
        try:
            q = ProfilesTable.insert().values(**profile_data)
            db.execute(q)
            return profile_id
        except sqlalchemy.exc.IntegrityError:
            q = (
                sql_select((ProfileRow.profile_id,))
                .where(ProfileRow.owner_id == owner_id)
                .where(ProfileRow.name == profile_name)
            )
            result = db.execute(q).fetchone()
            return result.profile_id
